using FytSoa.Application.Crm;
using FytSoa.Application.Crm.Param;
using FytSoa.Application.Erp.Param;
using FytSoa.Application.Sys;
using FytSoa.Common.Enum;
using FytSoa.Domain.Erp;
using FytSoa.Sugar;
using FytSoa.Common.Utils;
using FytSoa.Common.Param;
using FytSoa.Common.Result;
using FytSoa.Domain.Crm;
using FytSoa.Domain.Hr;
using FytSoa.Domain.Sys;
using FytSoa.DynamicApi.Attributes;
using Mapster;
using Masuit.Tools.Reflection;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;

namespace FytSoa.Application.Erp;

/// <summary>
/// erp_流程使用服务接口
/// </summary>
[ApiExplorerSettings(GroupName = "v9")]
public class ErpFlowUseService : IApplicationService 
{
    private readonly SugarRepository<ErpFlowUse> _thisRepository;
    private readonly SugarRepository<ErpFlow> _flowRepository;
    private readonly SugarRepository<HrEmployee> _employeeRepository;
    private readonly SugarRepository<ErpFlowAuditLog> _flowLogRepository;
    private readonly SysMessageService _messageService;
    public ErpFlowUseService(SugarRepository<ErpFlowUse> thisRepository
        ,SugarRepository<HrEmployee> employeeRepository
    ,SugarRepository<ErpFlow> flowRepository
        ,SugarRepository<ErpFlowAuditLog> flowLogRepository
        ,SysMessageService messageService)
    {
        _thisRepository = thisRepository;
        _employeeRepository = employeeRepository;
        _flowRepository = flowRepository;
        _flowLogRepository = flowLogRepository;
        _messageService = messageService;
    }
    
    /// <summary>
    /// 查询所有——分页
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    public async Task<PageResult<ErpFlowUseDto>> GetPagesAsync(PageParam param)
    {
        var query = await _thisRepository.AsQueryable()
            .OrderByDescending(m=>m.Id)
            .ToPageAsync(param.Page, param.Limit);
        return query.Adapt<PageResult<ErpFlowUseDto>>();
    }
    
    /// <summary>
    /// 查询使用者的流程配置，包括发起人
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    public async Task<List<ErpFlowDto.ErpFlowNodesDto>> GetUseConfigAsync(ErpFlowUserConfigParam param)
    {
        var flowUse = await _thisRepository.GetFirstAsync(m => m.UseId == param.UseId && m.FlowId == param.FlowId);
        var userIds = flowUse.Nodes.Select(m => m.EmployeeId);
        var userList = await _employeeRepository.AsQueryable()
            .Where(m => userIds.Contains(m.Id))
            .Includes(m=>m.OrganizationObj)
            .ToListAsync();
        var res = new List<ErpFlowDto.ErpFlowNodesDto>();
        foreach (var item in flowUse.Nodes)
        {
            var user = userList.FirstOrDefault(m => m.Id == item.EmployeeId);
            if(user==null) continue;
            res.Add(new ErpFlowDto.ErpFlowNodesDto()
            {
                EmployeeId = user.Id,
                Name = user.Name,
                Number = item.Number,
                Org = user.OrganizationObj.Name,
                Status = item.Status
            });
        }
        return res;
    }

    /// <summary>
    /// 自定义申请，用于行政相关
    /// </summary>
    [UnitOfWork]
    public async Task AddCurApplyAsync(ErpFlowUseDto model)
    {
        var flow = await _flowRepository.GetByIdAsync(model.FlowId);
        flow.Nodes.Insert(0,new ErpFlow.ErpFlowNodes()
        {
            Number = 0,
            EmployeeId = AppUtils.EmployeeId
        });
        model.Nodes = flow.Nodes.Adapt<List<ErpFlowUse.ErpFlowUseNodes>>();
        model.Nodes[1].Status = FlowAuditEnum.Await;
        var userId=await _thisRepository.InsertReturnSnowflakeIdAsync(model.Adapt<ErpFlowUse>());

        
        var addList = new List<ErpFlowAuditLog>
        {
            new ()
            {
                UseId = 0,
                FlowId = model.FlowId,
                FlowUseId=userId,
                PersonId=model.Nodes[0].EmployeeId,
                Status = FlowAuditEnum.Initiate,
                Type = model.Type,
                Title = FlowAuditEnum.Initiate.GetDescription()
            },
            new ()
            {
                UseId = 0,
                FlowId = model.FlowId,
                FlowUseId=userId,
                PersonId=model.Nodes[1].EmployeeId,
                Status = FlowAuditEnum.Await,
                Type = model.Type,
                Title = model.Type.GetDescription()+"审批流程："+FlowAuditEnum.Await.GetDescription()
            }
        };

        //增加记录，审批等待人
        await _flowLogRepository.InsertRangeAsync(addList);
        
        //发送提醒审核消息
        await _messageService.AddAsync(new SysMessageDto()
        {
            Types = MessageEnum.Approve,
            Title="您有一条待审批信息等您处理，请及时查看~",
            UserId=model.Nodes[1].EmployeeId
        });
    }
    

    /// <summary>
    /// 开始审批 
    /// </summary>
    /// <param name="useId"></param>
    /// <param name="typeEnum"></param>
    /// <returns></returns>
    [NonDynamicMethod,UnitOfWork]
    public async Task StartAuditAsync(long useId,FlowTypeEnum typeEnum)
    {
        var model = await _thisRepository.GetFirstAsync(m=>m.UseId==useId);
        model.Nodes[1].Status = FlowAuditEnum.Await;
        await _thisRepository.UpdateAsync(model);

        var addList = new List<ErpFlowAuditLog>
        {
            new ()
            {
                UseId = useId,
                FlowId = model.FlowId,
                FlowUseId=model.Id,
                PersonId=model.Nodes[0].EmployeeId,
                Status = FlowAuditEnum.Initiate,
                Type = typeEnum,
                Title = FlowAuditEnum.Initiate.GetDescription()
            },
            new ()
            {
                UseId = useId,
                FlowId = model.FlowId,
                FlowUseId=model.Id,
                PersonId=model.Nodes[1].EmployeeId,
                Status = FlowAuditEnum.Await,
                Type = typeEnum,
                Title = typeEnum.GetDescription()+"审批流程："+FlowAuditEnum.Await.GetDescription()
            }
        };

        //增加记录，审批等待人
        await _flowLogRepository.InsertRangeAsync(addList);
        
        //发送提醒审核消息
        await _messageService.AddAsync(new SysMessageDto()
        {
            Types = MessageEnum.Approve,
            Title="您有一条待审批信息等您处理，请及时查看~",
            UserId=model.Nodes[1].EmployeeId
        });
    }

    /// <summary>
    /// 审核业务
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    [UnitOfWork]
    public async Task ModifyAuditAsync(ErpFlowAuditParam param)
    {
        var logModel = await _flowLogRepository.GetByIdAsync(param.LogId);

        var useModel = await _thisRepository.GetByIdAsync(logModel.FlowUseId);

        if (param.Status==FlowAuditEnum.Agree)
        {
            // update nodes status
            var nodeIndex=useModel.Nodes.FindIndex(m => m.Status == FlowAuditEnum.Await);
            useModel.Nodes[nodeIndex].Status = FlowAuditEnum.Agree;
            logModel.Title = logModel.Type.GetDescription() + "审批流程：" + FlowAuditEnum.Agree.GetDescription();
            if (nodeIndex != useModel.Nodes.Count - 1)
            {
                useModel.Nodes[nodeIndex + 1].Status = FlowAuditEnum.Await;
                await _flowLogRepository.InsertAsync(new ErpFlowAuditLog()
                {
                    UseId = logModel.UseId,
                    FlowId = logModel.FlowId,
                    FlowUseId = logModel.FlowUseId,
                    PersonId = useModel.Nodes[nodeIndex + 1].EmployeeId,
                    Status = FlowAuditEnum.Await,
                    Type = logModel.Type,
                    Title = logModel.Type.GetDescription() + "审批流程：" + FlowAuditEnum.Await.GetDescription()
                });
                
                //发送提醒审核消息
                await _messageService.AddAsync(new SysMessageDto()
                {
                    Types = MessageEnum.Reject,
                    Title="您有一条待审批信息等您处理，请及时查看~",
                    UserId=useModel.Nodes[nodeIndex + 1].EmployeeId
                });
            }

            if (nodeIndex == useModel.Nodes.Count - 1)
            {
                // last 
                if (logModel.Type==FlowTypeEnum.Contract)
                {
                    var contractService = AppUtils.GetService<CrmContractService>();
                    await contractService.ModifyStatusAsync(new CrmContractStatusParam()
                    {
                        Id = new List<long>(){ useModel.UseId},
                        Status = CrmAuditEnum.Reviewed
                    });
                }
                if (logModel.Type==FlowTypeEnum.PayMent)
                {
                    var payMentService = AppUtils.GetService<CrmPaymentService>();
                    await payMentService.ModifyStatusAsync(new CrmContractStatusParam()
                    {
                        Id = new List<long>(){ useModel.UseId},
                        Status = CrmAuditEnum.Reviewed
                    });
                }
                if (logModel.Type==FlowTypeEnum.Invoice)
                {
                    var invoiceService = AppUtils.GetService<CrmInvoiceService>();
                    await invoiceService.ModifyStatusAsync(new CrmContractStatusParam()
                    {
                        Id = new List<long>(){ useModel.UseId},
                        Status = CrmAuditEnum.Reviewed
                    });
                }
                if (logModel.Type==FlowTypeEnum.Reimbursement)
                {
                    var reimbursementService = AppUtils.GetService<ErpFinanceReimbursementService>();
                    await reimbursementService.ModifyStatusAsync(new ErpStatusParam()
                    {
                        Ids = new List<long>(){ useModel.UseId},
                        Status = ErpAuditEnum.Reviewed
                    });
                }
                if (logModel.Type==FlowTypeEnum.FinancialPayment)
                {
                    var financePaymentService = AppUtils.GetService<ErpFinancePaymentService>();
                    await financePaymentService.ModifyStatusAsync(new ErpStatusParam()
                    {
                        Ids = new List<long>(){ useModel.UseId},
                        Status = ErpAuditEnum.Reviewed
                    });
                }
                if (logModel.Type==FlowTypeEnum.FinancialRefund)
                {
                    var financeRefundService = AppUtils.GetService<ErpFinanceRefundService>();
                    await financeRefundService.ModifyStatusAsync(new ErpStatusParam()
                    {
                        Ids = new List<long>(){ useModel.UseId},
                        Status = ErpAuditEnum.Reviewed
                    });
                }
                if (logModel.Type==FlowTypeEnum.ProductionOrder)
                {
                    var produceOrderService = AppUtils.GetService<ErpProduceOrderService>();
                    await produceOrderService.ModifyStatusAsync(new ErpStatusParam()
                    {
                        Ids = new List<long>(){ useModel.UseId},
                        Status = ErpAuditEnum.Reviewed
                    });
                }
                if (logModel.Type==FlowTypeEnum.PurchaseOrder)
                {
                    var purchaseOrderService = AppUtils.GetService<ErpPurchaseOrderService>();
                    await purchaseOrderService.ModifyStatusAsync(new ErpStatusParam()
                    {
                        Ids = new List<long>(){ useModel.UseId},
                        Status = ErpAuditEnum.Reviewed
                    });
                }
                if (logModel.Type==FlowTypeEnum.PurchaseReturn)
                {
                    var purchaseReturnService = AppUtils.GetService<ErpPurchaseReturnService>();
                    await purchaseReturnService.ModifyStatusAsync(new ErpStatusParam()
                    {
                        Ids = new List<long>(){ useModel.UseId},
                        Status = ErpAuditEnum.Reviewed
                    });
                }
                if (logModel.Type==FlowTypeEnum.InStock)
                {
                    var instockService = AppUtils.GetService<ErpInstockService>();
                    await instockService.ModifyStatusAsync(new ErpStatusParam()
                    {
                        Ids = new List<long>(){ useModel.UseId},
                        Status = ErpAuditEnum.Reviewed
                    });
                }
                if (logModel.Type==FlowTypeEnum.OutStock)
                {
                    var outstockService = AppUtils.GetService<ErpOutstockService>();
                    await outstockService.ModifyStatusAsync(new ErpStatusParam()
                    {
                        Ids = new List<long>(){ useModel.UseId},
                        Status = ErpAuditEnum.Reviewed
                    });
                }
                if (logModel.Type==FlowTypeEnum.TransferStock)
                {
                    var transferService = AppUtils.GetService<ErpTransferService>();
                    await transferService.ModifyStatusAsync(new ErpStatusParam()
                    {
                        Ids = new List<long>(){ useModel.UseId},
                        Status = ErpAuditEnum.Reviewed
                    });
                }
            }
            await _thisRepository.UpdateAsync(useModel);
            logModel.Status = FlowAuditEnum.Agree;
            await _flowLogRepository.AsUpdateable(logModel).UpdateColumns(it => new {it.Title,it.Status})
                .ExecuteCommandAsync();
        }
        if (param.Status==FlowAuditEnum.Reject)
        {
            logModel.Status = FlowAuditEnum.Reject;
            logModel.Title=logModel.Type.GetDescription() + "审批流程：" + FlowAuditEnum.Reject.GetDescription();
            if (logModel.Reject.Count == 0)
            {
                logModel.Reject = new List<ErpFlowAuditLog.ErpFlowAuditReject>();
            }
            logModel.Reject.Add(new ErpFlowAuditLog.ErpFlowAuditReject()
            {
                Cause = param.RejectCause,
                EmployeeId = AppUtils.EmployeeId
            });
            await _flowLogRepository.AsUpdateable(logModel).UpdateColumns(m => new {m.Status, m.Title, m.Reject})
                .ExecuteCommandAsync();
            
            var nodeIndex=useModel.Nodes.FindIndex(m => m.Status == FlowAuditEnum.Await);
            useModel.Nodes[nodeIndex].Status = FlowAuditEnum.Reject;
            await _thisRepository.AsUpdateable(useModel).UpdateColumns(m => new {m.Nodes})
                .ExecuteCommandAsync();
            
            //发送提醒审核消息
            await _messageService.AddAsync(new SysMessageDto()
            {
                Types = MessageEnum.Reject,
                Title="您有一条审批驳回信息等您处理，请及时查看~",
                UserId=useModel.Nodes[nodeIndex].EmployeeId
            });
        }
    }

    /// <summary>
    /// 回复驳回
    /// </summary>
    [UnitOfWork]
    public async Task PutReplyRejectAsync(ErpFlowReplyRejectParam param)
    {
        var logModel = await _flowLogRepository.GetByIdAsync(param.LogId);

        var useModel = await _thisRepository.GetByIdAsync(logModel.FlowUseId);
        
        logModel.Status = FlowAuditEnum.Await;
        logModel.Title=logModel.Type.GetDescription() + "审批流程：" + FlowAuditEnum.Await.GetDescription();
        logModel.Reject.Add(new ErpFlowAuditLog.ErpFlowAuditReject()
        {
            Type = 1,
            Cause = param.Reply,
            EmployeeId = AppUtils.EmployeeId
        });
        await _flowLogRepository.AsUpdateable(logModel).UpdateColumns(m => new {m.Status, m.Title, m.Reject})
            .ExecuteCommandAsync();
        
        var nodeIndex=useModel.Nodes.FindIndex(m => m.Status == FlowAuditEnum.Reject);
        useModel.Nodes[nodeIndex].Status = FlowAuditEnum.Await;
        await _thisRepository.AsUpdateable(useModel).UpdateColumns(m => new {m.Nodes})
            .ExecuteCommandAsync();
        
        //发送提醒审核消息
        await _messageService.AddAsync(new SysMessageDto()
        {
            Types = MessageEnum.Reject,
            Title="您有一条审批驳回信息等您处理，请及时查看~",
            UserId=useModel.Nodes[nodeIndex].EmployeeId
        });
    }

    /// <summary>
    /// 根据主键查询
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("{id}")]
    public async Task<ErpFlowUseDto> GetAsync(long id)
    {
        var model = await _thisRepository.GetByIdAsync(id);
        return model.Adapt<ErpFlowUseDto>();
    }
    
    /// <summary>
    /// 根据主键查询
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("{id}")]
    public async Task<ErpFlowDto.ErpFlowSimpleDto> GetFlowAsync(long id)
    {
        var flowUse = await _thisRepository.GetFirstAsync(m=>m.UseId==id);
        if (flowUse == null) return new ErpFlowDto.ErpFlowSimpleDto();
        var model = await _flowRepository.GetByIdAsync(flowUse.FlowId);
        return model.Adapt<ErpFlowDto.ErpFlowSimpleDto>();
    }

    /// <summary>
    /// 添加
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    public async Task AddAsync(ErpFlowUseDto model)
    {
        var flow = await _flowRepository.GetByIdAsync(model.FlowId);
        flow.Nodes.Insert(0,new ErpFlow.ErpFlowNodes()
        {
            Number = 0,
            EmployeeId = AppUtils.EmployeeId
        });
        model.Nodes = flow.Nodes.Adapt<List<ErpFlowUse.ErpFlowUseNodes>>();
        await _thisRepository.InsertAsync(model.Adapt<ErpFlowUse>());
    }

    /// <summary>
    /// 修改
    /// </summary>
    /// <param name="model"></param>
    /// <returns></returns>
    public async Task ModifyAsync(ErpFlowUseDto model)
    {
        var isAny = await _thisRepository.IsAnyAsync(m => m.UseId == model.UseId);
        if (!isAny)
        {
            //不存在，责任无修改了审批流程
            await _thisRepository.DeleteAsync(m => m.UseId == model.UseId);
            var flow = await _flowRepository.GetByIdAsync(model.FlowId);
            flow.Nodes.Insert(0,new ErpFlow.ErpFlowNodes()
            {
                Number = 0,
                EmployeeId = AppUtils.EmployeeId
            });
            model.Nodes = flow.Nodes.Adapt<List<ErpFlowUse.ErpFlowUseNodes>>();
            await _thisRepository.InsertAsync(model.Adapt<ErpFlowUse>());
        }
    }

    /// <summary>
    /// 删除,支持批量
    /// </summary>
    /// <param name="ids"></param>
    /// <returns></returns>
    [HttpDelete]
    public async Task DeleteAsync([FromBody] List<long> ids)
    {
        await _thisRepository.DeleteAsync(m=>ids.Contains(m.UseId));
        await _flowLogRepository.DeleteAsync(m => ids.Contains(m.UseId));
    }
}
